package ex3.render.raytrace;

import java.util.Map;
import math.*;

public class Disc extends Surface {
	protected Point3D center;
	protected double radius;
	protected Vec norm;

	/**
	 * Constructor creates disc surface object out of XML parsed attributes
	 * @param attributes
	 */
	public Disc(Map<String, String> attributes) {

		if (attributes.containsKey("center")) {
			center = new Point3D(attributes.get("center"));
		}
		if (attributes.containsKey("radius")) {
			radius = Double.valueOf(attributes.get("radius")).doubleValue();
		}
		if (attributes.containsKey("normal")) {
			norm = new Vec(attributes.get("normal"));
			norm.normalize();
		}
	}
	
	/**
	 * Ray-disc intersection algorithm
	 */
	public double nearestIntersection(Ray ray, boolean backFace) {
		// ray-disc intersection, similar to sphere
		
		// take the dot product of the vector-ray to the center and the norm, divided by
		// the ray-vector dot product with the norm to determine intersection
		double t = Point3D.sub(center, ray.p).dotProd(norm)
				/ ray.v.dotProd(norm);
		
		// if there is no intersection
		if (t < 0) {
			return Double.POSITIVE_INFINITY;
		}
		
		Point3D intersection = Point3D.add(Vec.scale(t, ray.v), ray.p);
		
		// if nearest intersection is larger than the radius, it's not of use to us
		if (intersection.sub(center).length() > radius) {
			return Double.POSITIVE_INFINITY;
		}
		
		
		double distance = Point3D.sub(intersection, ray.p).length();
		
		// if we looking at the disc's anterior face and 
		if (backFace == (Vec.dotProd(ray.v, norm) < 0)) {
			return Double.POSITIVE_INFINITY;
		} else return distance;
	}
	
	/**
	 * The norm vector itself
	 */
	public Vec normalAt(Point3D intersection, Ray ray) {
		return norm;
	}

	/**
	 * Generic constructor to be used in conjunction with init
	 */
	public Disc() {
	}

	public void init(Map <String,String> attributes) {
		if (attributes.containsKey("center")) {
			center = new Point3D(attributes.get("center"));
		}
		if (attributes.containsKey("radius")) {
			radius = Double.valueOf(attributes.get("radius")).doubleValue();
		}
		if (attributes.containsKey("normal")) {
			norm = new Vec(attributes.get("normal"));
			norm.normalize();
		}
	}
}